#ifndef ABCAMERA_H
#define ABCAMERA_H

#include <d3dx9math.h>
#include "Frustum.h"
#include "GameObject.h"

class ABCamera
{
public:
	ABCamera();
	virtual ~ABCamera();

	//////////////////////////////////////////////////////////////////////////
	// Update the camera. If it is attached or tracked, it will make movements
	//
	// Paramaters:
	// a_dt, the delta time
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	virtual void Update(float a_dt) = 0;

	//////////////////////////////////////////////////////////////////////////
	// Update the cameras frustum
	//
	// Paramaters:
	// m, the frustum is updated based on this matrix
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void UpdateFrustum(D3DXMATRIX& m);

	//////////////////////////////////////////////////////////////////////////
	// Get the view matrix of the camera
	//
	// Paramaters:
	// a_outViewMat, an out matrix that the view matrix is set to
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	virtual void GetViewMatrix(D3DXMATRIX& a_outViewMat) = 0;

	//////////////////////////////////////////////////////////////////////////
	// Get the eye position of the camera
	//
	// Paramaters:
	// None
	//
	// Returns a constant vector of the cameras positon	
	//
	//////////////////////////////////////////////////////////////////////////
	const D3DXVECTOR3& GetEyePos() const { return m_eyePos; }

	//////////////////////////////////////////////////////////////////////////
	// Set the yaw value of the camera
	//
	// Paramaters:
	// a_val, the value of the yaw to set
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void SetYaw(float a_val) { m_yawPitchRoll.x = a_val; }

	//////////////////////////////////////////////////////////////////////////
	// Set the pitch value of the camera
	//
	// Paramaters:
	// a_val, the value of the pitch to set
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void SetPitch(float a_val) { m_yawPitchRoll.y = a_val; }

	//////////////////////////////////////////////////////////////////////////
	// Set the roll value of the camera
	//
	// Paramaters:
	// a_val, the value of the roll to set
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void SetRoll(float a_val) { m_yawPitchRoll.z = a_val; }

	//////////////////////////////////////////////////////////////////////////
	// Get the yaw value
	//
	// Paramaters:
	// None
	//
	// Returns the yaw value of the camera
	//
	//////////////////////////////////////////////////////////////////////////
	float GetYaw() const { return m_yawPitchRoll.x; }

	//////////////////////////////////////////////////////////////////////////
	// Get the pitch value
	//
	// Paramaters:
	// None
	//
	// Returns the pitch value of the camera
	//
	//////////////////////////////////////////////////////////////////////////
	float GetPitch() const { return m_yawPitchRoll.y; }

	//////////////////////////////////////////////////////////////////////////
	// Get the roll value
	//
	// Paramaters:
	// None
	//
	// Returns the roll value of the camera
	//
	//////////////////////////////////////////////////////////////////////////
	float GetRoll() const { return m_yawPitchRoll.z; }

	//////////////////////////////////////////////////////////////////////////
	// Get whether or not the camera is active
	//
	// Paramaters:
	// None
	//
	// Returns true if this camera is active
	// Returns false if this camera is not active
	//
	//////////////////////////////////////////////////////////////////////////
	bool IsActive() { return m_isActive; }

	//////////////////////////////////////////////////////////////////////////
	// Activate or deactive the camera
	//
	// Paramaters:
	// a_val, the value to set
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void Activate(bool a_val) { m_isActive = a_val; }

	//////////////////////////////////////////////////////////////////////////
	// Get the viewing frustum of the camera
	//
	// Paramaters:
	// None
	//
	// Returns a pointer to the frustum being used
	//
	//////////////////////////////////////////////////////////////////////////
	Frustum* GetFrustum() const { return m_pFrustum; }

	//////////////////////////////////////////////////////////////////////////
	// Set the position of the camera
	//
	// Paramaters:
	// a_eye, the new position of the camera
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void SetEyePos(const D3DXVECTOR3& a_eye) { m_eyePos = a_eye; }

	//////////////////////////////////////////////////////////////////////////
	// Attach the camera to a game object
	//
	// Paramaters:
	// a_gameObject, a const reference to the game object to attach to
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void Attach(const GameObject& a_gameObject);

	//////////////////////////////////////////////////////////////////////////
	// Detach the camera from an object
	//
	// Paramaters:
	// None
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void Detach() { m_pAttached = NULL; }

	//////////////////////////////////////////////////////////////////////////
	// Get whether or not the camera is attached to an object
	//
	// Paramaters:
	// None
	//
	// Returns true if it is attached
	// Returns false if it's not attached
	//
	//////////////////////////////////////////////////////////////////////////
	bool IsAttached() const { return (m_pAttached != NULL); }

	//////////////////////////////////////////////////////////////////////////
	// Track a given object
	//
	// Paramaters:
	// a_gameObject, a const reference to the game object to be tracked
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void Track(const GameObject& a_gameObject);

	//////////////////////////////////////////////////////////////////////////
	// Stop tracking an object
	//
	// Paramaters:
	// None
	//
	// Returns void
	//
	//////////////////////////////////////////////////////////////////////////
	void Untrack() { m_pTracked = NULL; }

	//////////////////////////////////////////////////////////////////////////
	// Get whether or not the camera is tracking an object
	//
	// Paramaters:
	// None
	//
	// Returns true if the camera is tracking an object
	// Returns false if the camera is not tracking an object
	//
	//////////////////////////////////////////////////////////////////////////
	bool IsTracking() const { return (m_pTracked != NULL); }


private:

protected:
	// Eye position in world space
	D3DXVECTOR3 m_eyePos; 

	// Uses x,y,z components to store yaw,pitch,roll respectively
	D3DXVECTOR3 m_yawPitchRoll;  

	//Viewing frustum
	Frustum* m_pFrustum;

	//Whether or not this camera is active
	bool m_isActive;

	// Game object camera is attached to
	const GameObject* m_pAttached;  
	// Game object camera is tracking
	const GameObject* m_pTracked;
};

#endif //ABCAMERA_H